package tech.xs.sys.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import tech.xs.common.domain.enums.ImportTypeEnum;
import tech.xs.common.framework.domain.annotations.AuthApi;
import tech.xs.common.framework.domain.constant.DatePattern;
import tech.xs.common.framework.domain.constant.FileSuffixConstant;
import tech.xs.common.framework.domain.entity.BaseEntity;
import tech.xs.common.framework.domain.model.ApiResult;
import tech.xs.common.framework.domain.model.PageResult;
import tech.xs.common.framework.util.Assert;
import tech.xs.common.sys.domain.bo.SysConfigBo;
import tech.xs.common.sys.domain.constant.PermissionConstant;
import tech.xs.sys.domain.bo.config.EditConfigBo;
import tech.xs.sys.domain.bo.config.ExportConfigQueryBo;
import tech.xs.sys.domain.bo.config.ImportExportConfigBo;
import tech.xs.sys.domain.bo.config.PageConfigBo;
import tech.xs.sys.domain.entity.SysConfig;
import tech.xs.sys.service.SysConfigService;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Validated
@RestController
@RequestMapping("/config")
public class SysConfigController {

    @Resource
    private SysConfigService sysConfigService;

    @PostMapping("/saveOrUpdate")
    @AuthApi(permissions = PermissionConstant.PERMISSION_MGR)
    public ApiResult<SysConfig> manualEdit(@Validated @RequestBody EditConfigBo bo) {
        long existCount = sysConfigService.count(Wrappers.<SysConfig>lambdaQuery()
                .eq(SysConfig::getCode, bo.getCode())
                .ne(bo.getId() != null, BaseEntity::getId, bo.getId()));
        if (existCount > 0) {
            return ApiResult.error("编码已经存在");
        }

        SysConfig saveData = new SysConfig();
        BeanUtil.copyProperties(bo, saveData);
        if (bo.getId() != null) {
            SysConfig dbData = sysConfigService.getOne(Wrappers.<SysConfig>lambdaQuery().eq(BaseEntity::getId, bo.getId()));
            if (dbData == null) {
                return ApiResult.error("根据id在系统中未查询到数据");
            }
        }
        log.info("更新或保存配置:" + saveData);
        sysConfigService.saveOrUpdate(saveData);
        sysConfigService.deleteConfigCache(saveData.getCode());
        return ApiResult.success(saveData);
    }

    @DeleteMapping("/delete/id")
    @AuthApi(permissions = PermissionConstant.CONFIG_MGR)
    public ApiResult<Void> deleteByCode(@RequestParam Long id) {
        SysConfig config = sysConfigService.getById(id);
        if (config == null) {
            return ApiResult.error("配置不存在");
        }
        log.info("删除配置:" + config);
        sysConfigService.removeById(id);
        sysConfigService.deleteConfigCache(config.getCode());
        return ApiResult.success();
    }

    /**
     * 导出配置
     */
    @PostMapping("/export")
    @AuthApi(permissions = PermissionConstant.CONFIG_MGR)
    public ResponseEntity<List<ImportExportConfigBo>> exportConfig(@RequestBody ExportConfigQueryBo bo) {
        String fileName = "配置导出_" + DateUtil.format(new Date(), DatePattern.UNSIGNED_NORM_DATETIME_PATTERN) + FileSuffixConstant.JSON;
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        headers.add(HttpHeaders.CONTENT_TYPE, "application/json");

        List<ImportExportConfigBo> res = new ArrayList<>();
        if (CollUtil.isNotEmpty(bo.getIds())) {
            List<SysConfig> dbData = sysConfigService.list(bo.query());
            for (SysConfig dbItem : dbData) {
                ImportExportConfigBo exportItem = new ImportExportConfigBo();
                BeanUtil.copyProperties(dbItem, exportItem);
                exportItem.setImportType(ImportTypeEnum.addOrUpdate);
                res.add(exportItem);
            }
        }
        return ResponseEntity.ok().headers(headers).body(res);
    }

    /**
     * 导入配置
     */
    @PostMapping("/import")
    @AuthApi(permissions = PermissionConstant.CONFIG_MGR)
    public ApiResult<Void> importPermission(@NotNull @RequestParam("file") MultipartFile file) throws IOException {
        String json = new String(file.getBytes());
        List<ImportExportConfigBo> importDatas = JSONObject.parseArray(json, ImportExportConfigBo.class);
        log.info("开始导入配置:" + importDatas);
        for (ImportExportConfigBo importData : importDatas) {
            Assert.isNotBlank(importData.getCode(), "配置编码不能为空");
            Assert.isNotBlank(importData.getName(), "配置名称不能为空");
            Assert.isNotBlank(importData.getData(), "配置名称不能为空");
        }
        sysConfigService.importConfig(importDatas);
        log.info("配置导入成功:" + importDatas);
        return ApiResult.success();
    }

    @GetMapping("/list/page")
    @AuthApi(permissions = PermissionConstant.CONFIG_MGR)
    public PageResult<SysConfig> page(@ModelAttribute PageConfigBo bo) {
        return PageResult.success(sysConfigService.page(bo.page(), bo.query()));
    }

    @GetMapping("/getConfig")
    public ApiResult<SysConfigBo> getUserDetails(@RequestParam(value = "code") String code) {
        SysConfig config = sysConfigService.getOne(Wrappers.<SysConfig>lambdaQuery().eq(SysConfig::getCode, code));
        if (config == null) {
            return null;
        }
        SysConfigBo res = new SysConfigBo();
        res.setCode(config.getCode());
        res.setData(config.getData());
        res.setName(config.getName());
        return ApiResult.success(res);
    }


}
